﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Emit;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using static VBACodeingTool.VBEHelper;

namespace VBACodeingTool
{
    public delegate void CallBackShortCutCommand(Keys code, string shortCut);

    public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    public class KeyboardHook
    {
        private int _keyboardHook = 0;
        private int _mouseHook = 0;
        private const int WM_KEYDOWN = 0x0100;

        private LowLevelKeyboardProc _hookDelegate = null;
        private LowLevelKeyboardProc _mouseHookDelegate = null;
        private int WH_KEYBOARD = 2;
        private int WH_MOUSE = 7;
        public const int VK_SHIFT = 0x10;
        public const int VK_CONTROL = 0x11;
        public const int VK_MENU = 0x12; // Alt key

        //^V的时候不知道为什么会按 shift
        public static bool isInterceptShift = false;

        private bool isCheckKey = false;
        private IntPtr old = IntPtr.Zero;
        private IntPtr Hwnd { get; set; } = IntPtr.Zero;
        private bool isCheck = false;
        private string oldContent = "";

        public KeyboardHook(IntPtr hwnd)
        {
            Hwnd = hwnd;
        }

        #region keyBorad

        #region palne1

        private IntPtr HookCallbackAsync(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (Hwnd != User32.GetForegroundWindow())
            {
                return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
            }
            if (Hwnd != User32.GetForegroundWindow())
            {
                return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
            }

            Keys vkCode = (Keys)wParam;
            Int64 lParam32 = lParam.ToInt64();
            int bitPosition = 30;
            int mask = 1 << bitPosition;
            //获取第三十位参数意义是在这个消息之前按键的状态
            bool isBitZero = (lParam32 & mask) == 0;
            //Debug.WriteLine($"nCode:{nCode}-wParam:{wParam}-lParam:{Convert.ToString(lParam32, 2)}");
            if (nCode != 0 && isCheck)
            {
                return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
            }
            if (nCode == 0 && isBitZero)
            {
                isCheck = false;
                ShortCutAndPosition shortCutAndPosition = VBEHelper.GetShortCut();
                if (shortCutAndPosition.shortCut != null)
                {
                    oldContent = shortCutAndPosition.selfCodeAndPosition.Content;
                    if (isHitShortCut(vkCode, shortCutAndPosition.shortCut))
                    {
                        return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
                    }
                    if (IsTabAndPopupShow(vkCode, shortCutAndPosition.shortCut))
                    {
                        return (IntPtr)1;
                    }
                }
                return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
            }
            if (nCode == 3 && !isBitZero && !isCheck)
            {
                ShortCutAndPosition shortCutAndPosition = VBEHelper.GetShortCut();
                //Debug.WriteLine($"content:{shortCutAndPosition.selfCodeAndPosition.Content}");
                //Debug.WriteLine($"oldContent:{oldContent}");
                //Debug.WriteLine($"hookId{Thread.CurrentThread.ManagedThreadId}");
                if (shortCutAndPosition.shortCut != null)
                {
                    if (oldContent.Length < shortCutAndPosition.selfCodeAndPosition.Content.Length)
                    {
                        ProgramInstanceManager.ShortCut = shortCutAndPosition.shortCut;
                        FromHelper.HitCode(vkCode);
                    }
                }
                isCheck = true;
            }
            return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
        }

        #endregion palne1

        private bool IsTabAndPopupShow(Keys code, string shortCut)
        {
            if (code == Keys.Tab)
            {
                if (ProgramInstanceManager.Popup.IsShow)
                {
                    VBEHelper.InsertCurrentLineStr(ProgramInstanceManager.Popup.GetSelectedContent(),shortCut);
                    ProgramInstanceManager.Popup.CloseWindow();
                    return true;
                }
            }
            return false;
        }

        private bool isHitShortCut(Keys code, string shortCut)
        {
            RegisterKey register = new RegisterKey(IsKeyDown(VK_CONTROL), IsKeyDown(VK_SHIFT),
IsKeyDown(VK_MENU), code);
            if (ProgramInstanceManager.ShortCutManager.GetRun(register, code, shortCut))
            {
                return true;
            }
            return false;
        }

        #endregion keyBorad

        private IntPtr MouseHookCallBack(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (Hwnd != User32.GetForegroundWindow())
            {
                return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
            }
            if (nCode != 0)
            {
                return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
            }
            //wParam 514等于鼠标松开 160等于鼠标移动
            if (wParam.ToInt64() == 513)
            {
                if (ProgramInstanceManager.Popup.IsShow)
                {
                    if (!MouseHelper.IsMouseInForm(ProgramInstanceManager.Popup.Handle))
                    {
                        ProgramInstanceManager.Popup.CloseWindow();
                    }
                }
                //Debug.WriteLine($"Mouse:----nCode:{nCode}-wParam:{wParam}-lParam:{lParam}");
            }
            return User32.CallNextHookEx(WH_KEYBOARD, nCode, wParam, lParam);
        }

        public bool installHook()
        {
            if (_hookDelegate == null)
            {
                _hookDelegate = HookCallbackAsync;
            }

            _keyboardHook = User32.SetWindowsHookEx(WH_KEYBOARD, _hookDelegate, User32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), User32.GetCurrentThreadId());

            if (!isInstallHook())
            {
                System.Windows.Forms.MessageBox.Show("键盘钩子创建失败!");
                return false;
            }
            return true;
        }

        public bool installMouseHook()
        {
            if (_mouseHookDelegate == null)
            {
                _mouseHookDelegate = MouseHookCallBack;
            }
            _mouseHook = User32.SetWindowsHookEx(WH_MOUSE, _mouseHookDelegate, User32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), User32.GetCurrentThreadId());

            if (!isMouseInstallHook())
            {
                System.Windows.Forms.MessageBox.Show("鼠标钩子创建失败!");
                return false;
            }
            return true;
        }

        public void uninstallHook()
        {
            if (_keyboardHook != 0)
            {
                User32.UnhookWindowsHookEx(_keyboardHook);

                _keyboardHook = 0;
            }
        }

        public bool isInstallHook()
        {
            return _keyboardHook != 0 ? true : false;
        }

        public bool isMouseInstallHook()
        {
            return _mouseHook != 0 ? true : false;
        }

        public bool IsKeyDown(int keyCode)
        {
            short keyState = User32.GetKeyState(keyCode);

            return (keyState & 0x8000) != 0;
        }
    }

    public class RegisterKey
    {
        private bool isControl;
        private bool isShift;
        private bool isAlt;
        private Keys Key { set; get; }
        private CallBackShortCutCommand _callBackShortCutCommand = null;

        public RegisterKey(bool isControl, bool isShift, bool isAlt, Keys key)
        {
            this.isControl = isControl;
            this.isShift = isShift;
            this.isAlt = isAlt;
            Key = key;
            CreateName();
        }

        public RegisterKey(bool isControl, bool isShift, bool isAlt, Keys key, CallBackShortCutCommand callBackShortCutCommand)
        {
            this.isControl = isControl;
            this.isShift = isShift;
            this.isAlt = isAlt;
            Key = key;
            _callBackShortCutCommand = callBackShortCutCommand;
            CreateName();
        }

        public string name;

        private void CreateName()
        {
            name += this.isControl;
            name += this.isShift;
            name += this.isAlt;
            name += Key.ToString();
        }

        public void ExecuteDelegate(Keys code, string shortCut)
        {
            _callBackShortCutCommand?.Invoke(code, shortCut);
        }

        public void SetDelegate(CallBackShortCutCommand callBackShortCut)
        {
            _callBackShortCutCommand = callBackShortCut;
        }
    }

    public class ShortCutManager
    {
        private delegate void _currentCommand();

        private readonly List<RegisterKey> commands = new List<RegisterKey>();

        public void AddShortCut(RegisterKey registerCommand)
        {
            commands.Add(registerCommand);
        }

        public void AddShortCut(bool isControl, bool isShift, bool isAlt, Keys key, CallBackShortCutCommand callBackShortCutCommand)
        {
            RegisterKey registerCommand = new RegisterKey(isControl, isShift, isAlt, key);
            registerCommand.SetDelegate(callBackShortCutCommand);
            AddShortCut(registerCommand);
        }

        public bool GetRun(RegisterKey registerKey, Keys code, string shortCut)
        {
            foreach (RegisterKey registerCommand in commands)
            {
                if (registerKey.name == registerCommand.name)
                {
                    registerCommand.ExecuteDelegate(code, shortCut);
                    return true;
                }
            }
            return false;
        }
    }
}